Skip to content

Vehicles: real models for every car, train and boat, and for the signal heads - #1515

Merged
louis-e merged 3 commits into
mainfrom
vehicle-models
Nov 14, 2026
Merged

louis-e merged 3 commits into
mainfrom
vehicle-models

Conversation

@louis-e

@louis-e louis-e commented Nov 13, 2026 •

Copy link
Copy Markdown
Owner

Moving vehicles and traffic lights get real models instead of stretched blocks: 47 vehicles plus 6 signal-head states, built in Blockbench's format by a small Python kit, drawn on Java from the world's resource pack and on Bedrock from the add-on.

Vehicles

  • 47 models in assets/vehicles:
    • 9 car kinds: hatchback, sedan, estate, SUV, city car, van, pickup, lorry, bus.
    • 21 trains and freight wagons: tram (cab, middle, short), metro, S-Bahn (with a third-rail variant), regional, double-deck, ICE, locomotive, container/flat/tank/box wagons.
    • 17 ships and boats, with lowered _low builds for low bridges: motorboat, sailboat, river and car ferries, sea ferry, water bus, tour boat, peniche, barges, river cruise.
  • How it works:
    • kit.py paints each texel from the geometry.
    • build.py writes the textures, livery masks, Java item models, Bedrock geometry and metadata into out/, which Arnis embeds and recolours per livery.
    • check.py checks every model for flickering faces and for a blocked view from the rider's seat.
  • Java: each body is one item_display, with the brake lights on a second display.
    • Needs Java 1.21.6+ for the turned boxes; the tooltip and help now say so.
    • Verified on real 1.21.6 and 26.3 dedicated servers.
  • Bedrock: shared geometry per model and scale, a texture per livery, and wheels that turn with the car's speed.
  • Parked cars are the same models when moving vehicles are on (Java), with their lamps dark. One display each.
  • Atlas: each livery is a texture in the block atlas the facade photos share. Faces that change along one axis only are squeezed to a single texel row, losslessly (renders pixel-identical), which halved the textures. A test keeps every ship look under a third of an 8192² atlas, and the vehicles' share is reserved before facades are sized.

Traffic lights

  • One item_display per head, a model per state: red, amber, green, red-and-amber; walkers red and green. The data pack swaps the model, replacing 7 block displays per car head. The lit lens glows.
  • Mast arms are a straight bar at any angle instead of iron bars stepped along a diagonal.
  • Still Java 1.21.4+ (the signal models use no rotations).

Car behaviour fixes

Found by running a generated Hamburg world on a headless server and logging every car, body and head twice a second for several signal cycles:

  • Invisible lights: cars stopped at signals that had no head facing them, mostly crossings just past a junction on one-way carriageways, so they waited inside the junction. Cars now stop only where a car head faces them.
  • Over the stop line: a car stopped with its middle on the stop point, so the longer the car, the further its front reached over the line (a truck by 1.6 blocks). Each signal now has two stop points, one for cars and one further back for buses and trucks. Each is placed so the longest of its kind stops with its front a block short of the stop line the road markings paint, or just short of the signal where none is painted.
  • Waiting in junctions: a car about to cross a junction first checks there is room past it. It waits at the edge while a red light just past the junction, or a car standing at the start of the lane out heading its way, would leave it standing in the junction. Crossing traffic still gives way to its front. It gives up after 40 s, so cars waiting on each other in a ring get going.
  • Queues into junctions: turning cars treated a car standing ahead as crossing traffic and drove through it after a few seconds. Now they wait behind a car waiting at a red line, one standing in the lane ahead and heading much their way, or one ahead on the same way through (within 30° of their own heading).

Also

  • "New!" badges on Moving Vehicles and Working Traffic Lights.
  • Review fixes: Bedrock wheel-speed property range, texture decoding once per model, a warning when a user's own resources.zip keeps the models out, container wagons named by their colours.

Testing

  • cargo test: 2,629 passed. Integration tests pass, all GUI tests pass, clippy and fmt clean.
  • Every model passes check.py.
  • Java pack checked against the model rules: 0 problems across 163 models.
  • Real servers, 1.21.6 and 26.3: the data pack loads without errors, and car, train, boat and parked bodies carry their models.
  • Signal simulation, 150 s on 26.3 and 60 s on 1.21.6, then 180 s runs on 26.3 for the stop line and junction fixes:
    • every head showed its group's state at every sample (8,586 readings in the last run);
    • 0 of 117 stop-line crossings on red;
    • no car front over a painted stop line at any of the 17 lines seen, down from 6 of 13 before, measured from each body's model length;
    • overlapping bodies standing in lanes went from 51 readings to 1–6 a run; in total from 71 readings to 34–36;
    • held cars move off a median 0.5 s after green.

Known limitations

  • On Java 1.21.4/1.21.5 the vehicle models do not load (rotations), so vehicles show as missing models. resources.zip still declares format 46 because facades and the pause menu work there.
  • Parked cars and signal heads now need the world's resource pack, like facades. In singleplayer it loads with the world; a server has to offer it itself.
  • Cars still clip briefly where turning paths cross or merge inside a junction. Most of what remains is at lanes shorter than a car between two nodes of one junction: a car turning in cannot see one waiting at the lane's far end until it is in.
  • Cars look ahead along their heading, so one coming round a sharp bend can stop a little into a slow car just past it, for a few seconds.
  • A car waiting at a junction's edge stands at the lane's end like any car giving way there, its front a little into the crossing road.
  • A side road joining right at a signal has no stop for it.
  • Bedrock was checked as files (all JSON parses, the animation is wired up), not in the game.

…al heads

47 vehicle models and 6 signal-head states, built by a Python kit in
assets/vehicles (Blockbench's format, textures painted from the geometry,
livery masks, flicker and rider-view checks) and embedded from out/.

Java draws each body as one item_display from the world's resource pack
(1.21.6+), Bedrock as entity geometry with wheels that turn with speed.
Parked cars become the same models, lamps dark, when vehicles move on
Java. Signal heads are one display each, a model per state the data pack
swaps, and mast arms a straight bar at any angle.

Faces that change along one axis only take one texel row, losslessly,
which halved the atlas the vehicles share with facade photos; the
vehicles' share is set aside before facades are sized.

Cars stop only where a car head faces them, and queue behind a car held
at a red line instead of driving through it from inside a junction, as
a headless server run of Hamburg's junctions showed both going wrong.

Moving Vehicles and Working Traffic Lights get the New! badge.

Claude-Session: https://claude.ai/code/session_015UbtD55SJyhmbrZNKRYFdi
@github-actions

github-actions Bot commented Nov 13, 2026 •

Copy link
Copy Markdown

⏱️ Benchmark run finished in 0m 54s
🏗️ Generation time: 39s (excl. data fetching)
🧠 Peak memory usage: 1284 MB (↗ 2% more)

📈 Compared against baseline: 48s time, 1250 MB memory
🧮 Delta: -9s time, 34 MB memory
🔢 Commit: 0f61599

✅ This PR improves generation time.
⚠️ This PR increases peak memory.

📅 Last benchmark: 2026-11-14 01:26:38 UTC

You can retrigger the benchmark by commenting retrigger-benchmark.

Cars stopped with their middle on the stop point, so the longer the car, the
further its front reached over the line, a truck by 1.6 blocks. A signal's stop
is now two points, one for cars and one further back for buses and trucks, each
placed so the longest of its kind stands with its front a block short of the
stop line the road markings paint, or just short of the signal where none is.

A car about to cross a junction first checks for room past it: no red light too
close behind the junction to wait at clear of it, and no car standing across the
start of the lane out, heading its way. Otherwise it waits at the edge, for 40 s
at most. Inside a junction, a car standing in the lane ahead, or ahead on the
same way through, is a queue to wait behind, not crossing traffic to pass after
a while.

Claude-Session: https://claude.ai/code/session_015UbtD55SJyhmbrZNKRYFdi
From the review of the stop line and junction work:
- A stop line is looked for among every road's, by where it lies, so a line
  painted on the way before the signal's counts. Only one crossing this lane
  between its start and the signal does: not one beside some other stretch of
  road, which the old search pinned to the lane's end.
- A car waiting at the edge of a junction is not held as at a red line: its
  front can reach into the road it crosses, so crossing traffic gives way to it.
- The gate looks back over where a car joins a lane only where it joins partway
  along, not across a narrow junction at cars waiting on the far side.
- Inside a junction, a car standing in the lane past it counts as a queue only
  when it heads much the same way, and the same-way-through check measures from
  the car's own heading in sixteenths of a turn, read fresh, not the eighth look
  last left behind.
- Stops for two signal groups keep a point each. The gate's marks are cleared
  near the junction only, and a car already standing skips the gate.

Claude-Session: https://claude.ai/code/session_015UbtD55SJyhmbrZNKRYFdi
@louis-e
louis-e merged commit 8411e91 into main Nov 14, 2026
3 checks passed
@louis-e
louis-e deleted the vehicle-models branch November 14, 2026 09:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant